package com.chuangke.flowable.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.chuangke.admin.entity.SysUser;
import com.chuangke.admin.service.SysUserService;
import com.chuangke.common.db.page.CkPageQuery;
import com.chuangke.common.http.HttpResult;
import com.chuangke.common.utils.SecurityUtils;
import com.chuangke.flowable.domain.FlowableAuditRequest;
import com.chuangke.flowable.domain.FlowableSubmitRequest;
import com.chuangke.flowable.model.FlowableHandler;
import com.chuangke.flowable.service.FlowableService;

/**
 * {@code @Author:} stm
 * @Description:
 * @Date: Create in 2019/12/10 9:45
 */
@RestController
@RequestMapping(value = "flowable")
public class FlowableController {

    @Autowired
    private FlowableService flowableService;
    @Autowired
    private SysUserService sysUserService;

    /**
     * 启动流程
     *
     * @param flowableSubmitRequest
     * @return
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/submit")
    public HttpResult start(@RequestBody FlowableSubmitRequest flowableSubmitRequest) {
        SysUser user = sysUserService.findById(SecurityUtils.getUserId());
        HashMap<String, Object> map = new HashMap<>();
        FlowableHandler handler = new FlowableHandler();
        handler.setUserId(user.getId());
        handler.setDeptId(user.getDeptId());
        handler.setBusinessKey(flowableSubmitRequest.getBusinessKey());
        String processInstanceId = flowableService.startProcessInstance("demandPlan", handler, map);
        return HttpResult.ok("提交成功.流程Id为：" + processInstanceId);
    }

    /**
     * 审批
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "audit")
    public HttpResult auditAsync(@RequestBody FlowableAuditRequest flowableAuditRequest)
            throws InterruptedException, ExecutionException {
        SysUser user = sysUserService.findById(SecurityUtils.getUserId());

        List<CompletableFuture<Map<String, String>>> result = new ArrayList<>(
                flowableAuditRequest.getBusinessKeys().size());
        for (String businessKey : flowableAuditRequest.getBusinessKeys()) {
            FlowableHandler handler = new FlowableHandler();
            handler.setUserId(user.getId());
            handler.setDeptId(user.getDeptId());
            handler.setBusinessKey(businessKey);
            handler.setAudit(flowableAuditRequest.getAudit());
            result.add(flowableService.asyncComplete(handler, flowableAuditRequest.getMessage(), new HashMap<>()));
        }

        StringBuilder msg = new StringBuilder();
        StringBuilder errMsg = new StringBuilder();
        int failed = 0;
        for (CompletableFuture<Map<String, String>> mapCompletableFuture : result) {
            Map<String, String> rs = mapCompletableFuture.get();
            if (!"200".equals(rs.get("status"))) {
                if (failed < 1) {
                    errMsg.append(rs.get("msg")).append("<br/>");
                }
                failed++;
            }
        }
        msg.append(String.format("单据审批:【成功:%s条", result.size() - failed));
        if (failed > 0) {
            msg.append("；");
            msg.append(String.format("失败:(%s)条", failed));
            msg.append("】");
            msg.append("<br/>").append("<br/>");
            msg.append("失败提示：").append(errMsg);
        } else {
            msg.append("】");
        }

        return HttpResult.ok(msg.toString());
    }

    /**
     * 审批
     *
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "audit2")
    public HttpResult audit(@RequestBody FlowableAuditRequest flowableAuditRequest) {
        SysUser user = sysUserService.findById(SecurityUtils.getUserId());

        StringBuffer msg = new StringBuffer();
        StringBuilder errMsg = new StringBuilder();
        int failed = 0;

        for (String businessKey : flowableAuditRequest.getBusinessKeys()) {
            FlowableHandler handler = new FlowableHandler();
            handler.setUserId(user.getId());
            handler.setDeptId(user.getDeptId());
            handler.setBusinessKey(businessKey);
            handler.setAudit(flowableAuditRequest.getAudit());
            try {
                flowableService.complete(handler, flowableAuditRequest.getMessage(), new HashMap<>());
            } catch (Exception e) {
                failed++;
                errMsg.append(e.getMessage()).append("<br/>");
            }
        }

        msg.append(String.format("成功审批（%s）条单据", flowableAuditRequest.getBusinessKeys().size() - failed));
        if (failed > 0) {
            msg.append("；");
            msg.append(String.format("失败（%s）条单据", flowableAuditRequest.getBusinessKeys().size() - failed));
            msg.append("<br/>");
            msg.append(errMsg);
        }

        return HttpResult.ok(msg);
    }

    /**
     * 加载流程图
     *
     * @param businessKey
     * @return
     * @throws IOException
     */
    @PreAuthorize("hasAuthority('login:action')")
    @GetMapping(value = "/diagram/{businessKey}")
    public String diagram(@PathVariable String businessKey) throws IOException {
        byte[] imgBytes = flowableService.generateImageByBusinessKey(businessKey);
        return imgBytes == null ? "" : Base64.getEncoder().encodeToString(imgBytes);
    }

    /**
     * 加载流程节点审批信息
     *
     * @param businessKey
     * @return
     */
    @PreAuthorize("hasAuthority('login:action')")
    @GetMapping(value = "/nodes/{businessKey}")
    public HttpResult nodes(@PathVariable String businessKey) {
        return HttpResult.ok(flowableService.getFlowableNodeList(businessKey));
    }

    /**
     * 获取审批管理列表
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/todo")
    public HttpResult todoTask(@RequestBody Map<String, Object> params) {
        String userId = SecurityUtils.getUserId();
        params.put("userId", userId);
        return HttpResult.ok(flowableService.findTodoTask(new CkPageQuery(params)));
    }

    /**
     * 获取已办列表
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/done")
    public HttpResult doneTask(@RequestBody Map<String, Object> params) {
        String userId = SecurityUtils.getUserId();
        params.put("userId", userId);
        return HttpResult.ok(flowableService.findDoneTask(new CkPageQuery(params)));
    }

    /**
     * 获取已办结列表
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/doneandover")
    public HttpResult doneAndOverTask(@RequestBody Map<String, Object> params) {
        String userId = SecurityUtils.getUserId();
        params.put("userId", userId);
        return HttpResult.ok(flowableService.findDownAndOverTask(new CkPageQuery(params)));
    }

    /**
     * 获取我的单据列表
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/mycreated")
    public HttpResult myCreatedTask(@RequestBody Map<String, Object> params) {
        String userId = SecurityUtils.getUserId();
        params.put("userId", userId);
        return HttpResult.ok(flowableService.findMyCreatedTask(new CkPageQuery(params)));
    }

    /**
     * 获取我的退回单据
     */
    @PreAuthorize("hasAuthority('login:action')")
    @PostMapping(value = "/myreject")
    public HttpResult myRejectTask(@RequestBody Map<String, Object> params) {
        String userId = SecurityUtils.getUserId();
        params.put("userId", userId);
        return HttpResult.ok(flowableService.findRrejectTask(new CkPageQuery(params)));
    }

    @GetMapping(value = "/delete/{key}")
    public HttpResult counts(@PathVariable("key") String key) {
        flowableService.deleteProcessInstance(key);
        return HttpResult.ok();
    }

}
